package org.llc.common.starter.handle;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.llc.common.starter.util.UserUtils;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.llc.common.starter.constants.EnableDynamicAutEnum;

import java.util.Collection;
import java.util.stream.Collectors;

/**
 * 角色权限路由投票
 *
 * @author llc
 * @date 2020/1/13 16:57
 * @since 1.0.0
 */
@Slf4j
public class UrlRoleAuthVoter implements AccessDecisionVoter<Object> {

    /**
     * 用户认证信息工具类
     */
    private final UserUtils userUtils;

    public UrlRoleAuthVoter(UserUtils userUtils){
        this.userUtils = userUtils;
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return null != attribute.getAttribute();
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }


    /**
     * 选举
     * ACCESS_GRANTED – 同意
     * ACCESS_DENIED – 拒绝
     * ACCESS_ABSTAIN – 弃权
     *
     * @param user     用户认证信息
     * @param object   这个是访问的路径
     * @param urlRoles url
     * @return int
     * @author llc
     * @date 2020/1/19 12:24
     */
    @Override
    public int vote(Authentication user, Object object, Collection<ConfigAttribute> urlRoles) {
        // 默认弃权
        int result = ACCESS_ABSTAIN;
        Boolean flag = (Boolean) ((FilterInvocation)object).getRequest().getAttribute(EnableDynamicAutEnum.ENABLE_DYNAMIC_AUTH.getName());
        // 未启用则角色权限路由投票弃权或者此路径无需权限校验校验直接弃权
        if(!flag || CollectionUtils.isEmpty(urlRoles)){
            log.info("未启用角色权限路由投票则弃权或者此路径无需权限校验校验直接弃权");
            return result;
        }
        // 用户不存在
        if (null == user) {
            log.error("用户认证信息不存在");
            return ACCESS_DENIED;
        }
        // 获取用户角色权限
        Collection<String> userUtilsRoles = userUtils.getCurrentSimpleAuthorities();
        // 接口所需要的角色权限
        Collection<String> stringCollection = urlRoles
                .stream()
                .map(String::valueOf)
                .filter(configAttribute -> configAttribute.contains(EnableDynamicAutEnum.ENABLE_DYNAMIC_AUTH.getPrefix()))
                .map(s -> s.replaceFirst(EnableDynamicAutEnum.ENABLE_DYNAMIC_AUTH.getPrefix(),""))
                .collect(Collectors.toSet());
        // 如果包含全部所需要角色权限
        if (userUtilsRoles.containsAll(stringCollection)) {
            log.info("权限校验通过");
            result = ACCESS_GRANTED;
        }
        return result;
    }
}
